package com.unibeta.cloudtest.mesher.controller;

import java.io.File;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.unibeta.cloudtest.mesher.auth.annotation.Authorization;
import com.unibeta.cloudtest.mesher.auth.context.AuthContextHolder;
import com.unibeta.cloudtest.mesher.config.ConfigurationProxy;
import com.unibeta.cloudtest.mesher.dto.CloudTest;
import com.unibeta.cloudtest.mesher.dto.OpenAPI2Case;
import com.unibeta.cloudtest.mesher.dto.R;
import com.unibeta.cloudtest.mesher.dto.TreeModel;
import com.unibeta.cloudtest.mesher.service.EditorService;
import com.unibeta.cloudtest.mesher.util.Log;
import com.unibeta.cloudtest.openapi.tool.OpenAPI2TestCases;

import io.swagger.annotations.Api;

@Api(value = "CloudTest.Editor", tags = "CloudTest.Editor")
@RestController
@RequestMapping("/mesher")
@Authorization
public class MesherEditorController {
	@Autowired
	EditorService editorService;

	@PostMapping("/convert")
	public R<String> convert(@RequestBody OpenAPI2Case openAPI2Case) {
		String caseXml = null;
		String fullPath = ConfigurationProxy.getCloudTestRootPath() + openAPI2Case.getCasePath();

		if (new File(fullPath).exists()) {
			return R.fail("'" + openAPI2Case.getCasePath() + "' already exists, please rename the case file path.");
		}

		try {
			String[] matchers = null;
			if (!StringUtils.isBlank(openAPI2Case.getTagMatchers())) {
				matchers = openAPI2Case.getTagMatchers().split(",");
			}

			caseXml = OpenAPI2TestCases.digestToTestCases(openAPI2Case.getApiDocs(), matchers,
					openAPI2Case.getCasePath());
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok(caseXml);
	}

	@GetMapping("/editor/filetree")
	public R<List<TreeModel>> getFileTree() {

		List<TreeModel> list = null;
		try {
			list = editorService.getFileTree(ConfigurationProxy.getCloudTestRootPath());
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok(list);
	}

	@GetMapping("/editor/loadfile")
	public R<CloudTest> loadFile(@RequestParam("caseUri") String caseUri) {

		CloudTest cloudtest = null;
		try {
			cloudtest = editorService.load(ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok(cloudtest);
	}

	@PostMapping("/editor/savefile")
	public R saveFile(@RequestBody(required = false) String content, @RequestParam("caseUri") String caseUri) {

		try {
			String filePath = ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri;
			File file = new File(filePath);

			if (file.isDirectory()) {
				return R.fail("given path is not a file");
			}

			if (!file.canWrite()) {
				file.setWritable(true);
			}

			editorService.save(content, filePath);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok();
	}

	@PostMapping("/editor/newfile")
	public R newFile(@RequestParam("caseUri") String caseUri) {

		try {
			String filePath = ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri;

			editorService.newFile(filePath);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok();
	}

	@PostMapping("/editor/newfolder")
	public R newFolder(@RequestParam("caseUri") String caseUri) {

		try {
			String filePath = ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri + "/";

			editorService.newFolder(filePath);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok();
	}

	@PostMapping("/editor/deletefile")
	public R delete(@RequestParam("caseUri") String caseUri) {

		try {
			String filePath = ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri;

			editorService.deleteFile(filePath);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}

		return R.ok();
	}

	@PostMapping("/editor/run")
	public R<CloudTest> run(@RequestBody CloudTest cloudtest) {

		try {
			CloudTest c = editorService.run(cloudtest);
			return R.ok(c);
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

	@PostMapping("/editor/restore")
	public R restore() {
		try {
			editorService.restoreWorkspace(AuthContextHolder.getContext().getCurrentUserDetails().getUsername());
			return R.ok();
		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

	@Authorization
	@PostMapping(value = "/editor/importfile")
	public R<String> importFile(@RequestParam("basePath") String basePath, @RequestBody MultipartFile file) {
		try {
			String destPath = ConfigurationProxy.getCloudTestRootPath() + "/" + basePath;
			if ("$CLOUDTEST_HOME$".equalsIgnoreCase(basePath)) {
				destPath = ConfigurationProxy.getCLOUDTEST_HOME();
			}

			String importFile = editorService.importFile(destPath, file);
			if (!StringUtils.isBlank(importFile)) {
				return R.ok(importFile);
			} else {
				return R.fail("import file is null.");
			}

		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

	@Authorization
	@PostMapping(value = "/editor/exportfile")
	public R<String> exportFile(@RequestParam("basePath") String basePath) {
		try {

			String exportPath = ConfigurationProxy.getCloudTestRootPath();

			if (!StringUtils.isBlank(basePath)) {
				exportPath = ConfigurationProxy.getCloudTestRootPath() + "/" + basePath;
			}

			String exportFile = editorService.exportFile(exportPath).replace("\\", "/");

			String workspace = ConfigurationProxy.getWorkspace().replace("\\", "/");

			String workspaceUri = "/workspace";
			if (workspace.endsWith("/")) {
				workspaceUri = "/workspace/";
			} else {
				workspaceUri = "/workspace";
			}

			String downloadUrl = exportFile.replace(workspace, ConfigurationProxy.getAPIHost() + workspaceUri)
					.replace("\\", "/");

			if (!StringUtils.isBlank(downloadUrl)) {
				return R.ok(downloadUrl);
			} else {
				return R.fail("export file is null.");
			}

		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

	@Authorization
	@PostMapping(value = "/editor/duplicatefile")
	public R<String> duplicateFile(@RequestParam("caseUri") String caseUri) {
		try {
			return R.ok(editorService.duplicateFile(ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri)
					.substring(ConfigurationProxy.getCloudTestRootPath().length()));

		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

	@Authorization
	@PostMapping(value = "/editor/renamefile")
	public R<String> renameFile(@RequestParam("caseUri") String caseUri, @RequestParam("newName") String newName) {
		try {

			return R.ok(editorService.renameFile(ConfigurationProxy.getCloudTestRootPath() + "/" + caseUri, newName)
					.substring(ConfigurationProxy.getCloudTestRootPath().length()));

		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}
	
	@Authorization
	@PostMapping(value = "/editor/clearCache")
	public R<String> clearCache() throws Exception {
		try {
			editorService.clearCache();
			return R.ok("success");

		} catch (Exception e) {
			Log.getLogger().error(e.getMessage(), e);
			return R.fail(e.getMessage());
		}
	}

}
